package testing;

import java.util.ArrayList;

import Shapes.Ball;
import Shapes.Box2D;
import Shapes.Edge;
import Shapes.Flow;
import Shapes.parallelCoordinates;
import Shapes.pieBall;

import processing.core.*;

public class testView extends PApplet {

	/**
	 * Springs.
	 * 
	 * Move the mouse over one of the circles and click to re-position. When you
	 * release the mouse, it will snap back into position. Each circle has a
	 * slightly different behavior.
	 */

	int num_process = 6; // now we set it as 6
	
	Element[] button_process = new Element[num_process]; // the process button
	PImage[] processsprite = new PImage[num_process]; // the pic for the process_sprite
	float radium = 250;
	
	int num_impact = 2; // now we set it as 6
	Element[] button_impact = new Element[num_impact]; // the process button
	PImage[] impactsprite = new PImage[num_impact]; // the pic for the process_sprite
	int selected_impact = 0;
	
	pieBall central_impact = null;
	
	
	
	//what's in the statistics data
	ArrayList<Element> process = new ArrayList<Element>();
	ArrayList<Flow> flows = new ArrayList<Flow>();
	
	//which process has been selected
	int partX = 0;
	int partY = 0;
	boolean isQueried = false;
	boolean isQueryFixed = false;
	Box2D queryBox = null;
	
	//draw parallelCoordinates
	parallelCoordinates conditions = null;
	

	// open another view
	radiation r = new radiation();

	PFont fontA;

	
	boolean isAdd = false;
	int sectionX = 0;
	int settionY = 0;

	public void setup() {
		size(1200, 800);
		noStroke();
		smooth();

		// setup Font
		// Load the font. Fonts must be placed within the data
		// directory of your sketch. Use Tools > Create Font
		// to create a distributable bitmap font.
		// For vector fonts, use the createFont() function.
		fontA = loadFont("../resource/Ziggurat-32.vlw");

		// Set the font and its size (in units of pixels)
		textFont(fontA, 20);

		// ----------------------------here we give six kind of
		// processing------------------------------//

		int width_process_interval = this.width / (num_process + 1);

		for (int i = 0; i < num_process; i++) {
			String name = "";
			switch (i) {
			case 0:
				name = "farming";
				break;
			case 1:
				name = "manufacturing";
				break;
			case 2:
				name = "transportation";
				break;
			case 3:
				name = "retail";
				break;
			case 4:
				name = "storage";
				break;
			case 5:
				name = "cooking";
				break;
			}
			
			button_process[i] = new Element(width_process_interval * (i + 1), 30, 50, 0.9f,
					10.0f, 0.1f, button_process, i, name, 1);
		
		}
		
		int height_impact_interval = this.height / (num_impact + 1);
		
		for (int i = 0; i < num_impact; i++) {
			String name = "";
			switch (i) {
			case 0:
				name = "energy consuming";
				break;
			case 1:
				name = "land requirement";
				break;
			}
			button_impact[i] = new Element(20,height_impact_interval * (i + 1), 50, 0.9f,
					10.0f, 0.1f, button_impact, i, name, 2);
		}
		
		// ----------------------------------------------------------//
		// ----------------------------here we give six kind of
		// pictures------------------------------//
		processsprite[0] = loadImage("../resource/farming.gif");
		processsprite[1] = loadImage("../resource/manufacturing.gif");
		processsprite[2] = loadImage("../resource/transportation.gif");
		processsprite[3] = loadImage("../resource/retail.gif");
		processsprite[4] = loadImage("../resource/storage.gif");
		processsprite[5] = loadImage("../resource/cooking.gif");

		impactsprite[0] = loadImage("../resource/storage.gif");
		impactsprite[1] = loadImage("../resource/cooking.gif");
		
		
		//prepare the impact in the middle
		central_impact = new pieBall(this);
		
		central_impact.setup("../resource/con1997.txt", this.width/2, this.height/2);
		
		r = new radiation();
		
		//prepare the querybox
	    queryBox = new Box2D(this);
		queryBox.setup(0, 0, 0);
		
		//prepare the conditions
		conditions = new parallelCoordinates(this);
		conditions.setup();
		
	}

	
	
	public void draw() {
	//	background(0);
		
		fill(0, 21);
		rect(0, 0, width, height);
		

		// draw big ball which is in the middle of the view
		//here we are going to link this data to entities, now by size
        float impact_width = 200;
        float impact_height = 200;
  
    	
	//	ellipse(this.width / 2, this.height / 2, impact_width, impact_height);
		
   // 	this.central_impact.update();
		//which impact is selected.
		image(impactsprite[selected_impact], this.width / 2 - 30, this.height / 2 - 30, 60, 60);
	

		// draw process
		for (int i = 0; i < num_process; i++) {
			button_process[i].update();
			button_process[i].display();
		}
		
		//draw links between this process
		drawLinks();
		
		//draw particle system to show the material flow in this pipeline
		for (int i = 0; i < flows.size(); i++) {
			flows.get(i).draw();
		}
		
		// draw impact
		for (int i = 0; i < num_impact; i++) {
			button_impact[i].update();
			button_impact[i].display();
		}
		// draw selecting windows
		if (isQueried) {
	
			stroke(153);
			if(!isQueryFixed){
				queryBox.update(mouseX, mouseY, 0);
				queryBox.draw();
			    partX = mouseX;
			    partY = mouseY;
			}else{
				queryBox.update(partX,partY,0);
				queryBox.draw();
			}
		}

		//draw labels
		for (int n = 0; n < process.size(); n++) {
			// process.get(n).update();
			process.get(n).display();
	//		text(process.get(n).name, process.get(n).xpos, process.get(n).ypos);
		}
		
		//draw parallelCoordinates
		conditions.draw();
		
		//draw central impact;
    	central_impact.draw();


	}


	private void drawLinks() {
		// TODO Auto-generated method stub
		
		if(process.size() == 0)
		{
			return;
		}
		int num = process.size() -1;
		Edge[] links = new Edge[num]; // the process button
		for(int i = 0; i < num; i++)
		{
			links[i] = new Edge(this);
			links[i].setup(process.get(i).xpos, process.get(i).ypos, 0, process.get(i+1).xpos, process.get(i+1).ypos, 0);
		}
		
		for(int i = 0; i < num; i++)
		{	
			links[i].draw();
		}
		
		
	}



	public void keyPressed() {

		if (key == 'q') {
			isQueried = !isQueried;
		} 
		
		if(key == 'f'){
			isQueryFixed = !isQueryFixed;
		}
		
		if( key == 's'){
			
			r.start();
		}

	}
	
	public void mouseClicked(){
		
	}

	public void mousePressed() {
		for (int i = 0; i < num_process; i++) {
			button_process[i].pressed();
		}
		
		for (int i = 0; i < num_impact; i++) {
			button_impact[i].pressed();
		}
		
		for(int i = 0; i < process.size(); i++){
			process.get(i).pressed();
		}
		
		conditions.mousePressed();
	}

	public void mouseMoved() {
		for (int i = 0; i < num_process; i++) {
			button_process[i].mousePassby();
		}
		
		for(int i = 0; i < num_impact; i ++)
		{
			button_impact[i].mousePassby();
		}
		
		for(int i = 0; i< process.size();i++){
			process.get(i).mousePassby();
		}
	}
	
	public void mouseReleased() {

		// this is for the indicators, we choose
		int ispressed = -1;
		int selectType = 1;
		for (int i = 0; i < num_process; i++) {
			button_process[i].released();
			if (button_process[i].isPressed() == true) {
				ispressed = i;
			}
		}
		
		if(ispressed == -1){
			selectType = 2;
			for (int i = 0; i < num_impact; i++) {
				button_impact[i].released();
				if (button_impact[i].isPressed() == true) {
					ispressed = i;
				}
			}
			
			if(ispressed == -1)
			{
				selectType = -1;
			}
		}
		
		if (selectType == 1) {
			// add one into the circle
			PVector d1 = new PVector(this.mouseX, this.mouseY);
			float distance = d1.dist(new PVector(this.width / 2,
					this.height / 2));

			if (distance < 150) {
				if (ispressed >= 0) {
					this.isAdd = true;
					// get the location for this member
					addOneProcess(button_process[ispressed].name, 1,
							getPosition());
				}
				this.isAdd = false;
			}
		} else if (selectType == 2) {

			//which impact is selected.
			
           this.selected_impact = ispressed;			
		}
		
		// this is for the processes we created
		
		//this is for the conditions
		conditions.mouseReleased();
	}

	private int getPosition() {
		// TODO Auto-generated method stub

		if (process.size() == 0) {
			return 0;
		}
		int position = 0;
		float distance = 1000;
		for (int i = 0; i < process.size(); i++) {
			PVector m = new PVector(process.get(i).xpos, process.get(i).ypos);
			float tem = m.dist(new PVector(this.mouseX, this.mouseY));
			if (distance > tem) {
				distance = tem;
				position = i;
			}
		}

		float temx = process.get(position).tempxpos;
		float temy = process.get(position).tempypos;

		if ((this.sectionX > this.width / 2)
				&& (this.settionY > this.height / 2)) {
			if ((this.sectionX < temx) && (this.settionY > temy)) {
			} else {
				position += 1;
			}
		} else if ((this.sectionX > this.width / 2)
				&& (this.settionY < this.height / 2)) {
			{
				if ((this.sectionX > temx) && (this.settionY > temy)) {
				} else {
					position += 1;
				}
			}
		} else if ((this.sectionX < this.width / 2)
				&& (this.settionY < this.height / 2)) {
			if ((this.sectionX > temx) && (this.settionY < temy)) {
			} else {
				position += 1;
			}
		} else {
			if ((this.sectionX > temx) && (this.settionY > temy)) {
			} else {
				position += 1;
			}
		}
		return position;
	}

	private void addOneProcess(String name,int type, int position) {
		// TODO Auto-generated method stub

		int num = process.size();
		Element newprocess = new Element(0, 0, 50, 0.98f, 8.0f, 0.1f, button_process,num+1,
				name, type);

		process.add(newprocess);
		for (int change = process.size() - 1; change > position; change--) {
			process.set(change, process.get(change - 1));
		}
		process.set(position, newprocess);

		float angle = (float) (2 * Math.PI * 1.0 / (num + 1));
		System.out.println(num + 1);
		System.out.println(angle);

		for (int n = 0; n < num + 1; n++) {
			process.get(n).xpos = this.width / 2
					+ (float) (radium * Math.sin(angle * n));
			process.get(n).ypos = this.height / 2
					- (float) (radium * Math.cos(angle * n));

			process.get(n).tempxpos = process.get(n).xpos;
			process.get(n).tempypos = process.get(n).ypos;
		}
		
		//after get the new Arraylist, we have to renew
		flows.clear();
		for(int i = 0; i < process.size()-1;i++)
		{
			Flow f = new Flow(this);
			PVector ori = new PVector(process.get(i).xpos,process.get(i).ypos);
			PVector des = new PVector(process.get(i+1).xpos,process.get(i+1).ypos);
			f.setup(5, ori, des);
			flows.add(f);
		}

	}

	

	public class Element {
		// Screen values
		float xpos, ypos;
		float tempxpos, tempypos;
		int size = 20;
		boolean over = false;
		boolean move = false;

		// Spring simulation constants
		float mass; // Mass
		float k = 0.2f; // Spring constant
		float damp; // Damping
		float rest_posx; // Rest position X
		float rest_posy; // Rest position Y

		// Spring simulation variables
		// float pos = 20.0; // Position
		float velx = 0.0f; // X Velocity
		float vely = 0.0f; // Y Velocity
		float accel = 0; // Acceleration
		float force = 0; // Force

		Element[] friends;
		int me;
		String name = "";
		int type; // 1- process 2-impact

		// Constructor
		Element(float x, float y, int s, float d, float m, float k_in,
				Element[] others, int id, String name, int type) {
			xpos = tempxpos = x;
			ypos = tempypos = y;
			rest_posx = x;
			rest_posy = y;
			size = s;
			damp = d;
			mass = m;
			k = k_in;
			friends = others;
			me = id;
			this.name = name; 
            this.type = type;
		
		}

		public void update() {
			if (move) {
				rest_posy = mouseY;
				rest_posx = mouseX;
			}

			force = -k * (tempypos - rest_posy); // f=-ky
			accel = force / mass; // Set the acceleration, f=ma == a=f/m
			vely = damp * (vely + accel); // Set the velocity
			tempypos = tempypos + vely; // Updated position

			force = -k * (tempxpos - rest_posx); // f=-ky
			accel = force / mass; // Set the acceleration, f=ma == a=f/m
			velx = damp * (velx + accel); // Set the velocity
			tempxpos = tempxpos + velx; // Updated position

			if ((over() || move) && !otherOver()) {
				over = true;
			} else {
				over = false;
			}
		}

		// Test to see if mouse is over this spring
		public boolean over() {
			float disX = tempxpos - mouseX;
			float disY = tempypos - mouseY;
			if (sqrt(sq(disX) + sq(disY)) < size / 2) {
				return true;
			} else {
				return false;
			}
		}

		// Make sure no other springs are active
		public boolean otherOver() {
			if(type ==1){
				for (int i = 0; i < num_process; i++) {
					if (i != me) {
						if (friends[i].over == true) {
							return true;
						}
					}
				}
			}else if (type == 2)
			{
				for (int i = 0; i < num_impact; i++) {
					if (i != me) {
						if (friends[i].over == true) {
							return true;
						}
					}
				}
			}
			return false;
		}

		public void display() {
			if (over) {

				fill(255);
				text(name, 850, 300);

				fill(153);

			} else {
				fill(255);
			}
			// ellipse(tempxpos, tempypos, size, size);
			int picindex = -1;

			if (type == 1) {
				if (name.equalsIgnoreCase("farming")) {
					picindex = 0;
				} else if (name.equalsIgnoreCase("manufacturing")) {
					picindex = 1;
				} else if (name.equalsIgnoreCase("transportation")) {
					picindex = 2;
				} else if (name.equalsIgnoreCase("retail")) {
					picindex = 3;
				} else if (name.equalsIgnoreCase("storage")) {
					picindex = 4;
				} else if (name.equalsIgnoreCase("cooking")) {
					picindex = 5;
				}

				image(processsprite[picindex], tempxpos - 30, tempypos - 30,
						60, 60);
			} else if (type == 2) {
				if (name.equalsIgnoreCase("energy consuming")) {
					picindex = 0;
				} else if (name.equalsIgnoreCase("land requirement")) {
					picindex = 1;
				} 

				image(impactsprite[picindex], tempxpos - 30, tempypos - 30,
						60, 60);
			}
		}

		public void pressed() {
			if (over) {
				move = true;
			} else {
				move = false;
			}
		}

		public void released() {
			move = false;
			rest_posx = xpos;
			rest_posy = ypos;

		}

		public boolean isPressed() {
			if (over) {
				return true;
			} else {
				return false;
			}
		}

		public void mousePassby() {
		}
	}

}
